#include "Thread.hpp"
#include <vector>
#include <queue>
#include <mutex>
#include "Log.hpp"

using namespace LogModule;
using namespace ThreadModule;

using task_t= function<void()>;

class ThreadPool
{
    void HandleTask()
    {
         char name[80];
        pthread_getname_np(pthread_self(), name, 80);
        LOG(LogLevel::INFO)<<name<<" 开始运行"; 
        
        while(1)
        {
           

            pthread_mutex_lock(&_mutex);

            if(_q.empty() && _isrunning)
            {
                //任务队列为空，但线程池还在跑，那该线程就在条件变量上等
                _waitnum++;
                pthread_cond_wait(&_cond, &_mutex);
                _waitnum--;
            }

            if(_q.empty() && !_isrunning)
            {
                pthread_mutex_unlock(&_mutex);
                break;
            }

            //任务队列不为空，那不管线程池跑不跑了都得执行完任务，所以该线程取任务，并执行
            task_t t= _q.front();
            _q.pop();
            pthread_mutex_unlock(&_mutex);

            t();
        }
        
    }

public:
    ThreadPool(int threadnum)
    :_threadnum(threadnum)
    {
        LOG(LogLevel::DEBUG)<<"线程池初始化线程的名字，还有要运行的函数";
        for(int i=0;i<_threadnum;i++)
            _pool.push_back({bind(&ThreadPool::HandleTask, this)});
    }

    ThreadPool(const ThreadPool&)= delete;//单例模式禁用拷贝
    ThreadPool& operator=(const ThreadPool&)= delete;

    void Start()
    {
        LOG(LogLevel::DEBUG)<<"线程池开始让线程运行";

        pthread_mutex_lock(&_mutex);

        _isrunning= true;
        for(int i=0;i<_threadnum;i++)
            _pool[i].Start();

        pthread_mutex_unlock(&_mutex);
    }

    void Join()
    {
         LOG(LogLevel::DEBUG)<<"线程池开始回收线程";
        for(int i=0;i<_threadnum;i++)
        {
            _pool[i].Join();
        }
    }

    void Stop()
    {

        LOG(LogLevel::DEBUG)<<"线程池停止添加任务";
        pthread_mutex_lock(&_mutex);

        _isrunning= false;
        if(_waitnum> 0)
        {
            pthread_cond_broadcast(&_cond);//唤醒等待的线程
        }
        pthread_mutex_unlock(&_mutex);
    }

    void Enqueue(task_t t)
    {
        
        pthread_mutex_lock(&_mutex);

        if(_isrunning== false)//读共享资源需要加锁，不然刚读完就被改了，执行流就不对了
        {
            pthread_mutex_unlock(&_mutex);
            return ;
        }

        _q.push(t);
        if(_waitnum> 0)
        {
            pthread_cond_signal(&_cond);//保持线程同步
        }

        pthread_mutex_unlock(&_mutex);
    }
    
    static ThreadPool* GetInstance()
    {
        pthread_mutex_lock(&mut);

        if(tp== nullptr)
        {
           tp =new ThreadPool(5);
        }
        
        pthread_mutex_unlock(&mut);

        return tp;
    }
private:
    int _threadnum;
    vector<Thread> _pool;

    queue<task_t> _q;
    int _waitnum= 0;//在条件变量上等待获取任务的线程个数
    pthread_mutex_t _mutex= PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t _cond= PTHREAD_COND_INITIALIZER;

    bool _isrunning;

    static ThreadPool* tp;//类内声明
    static pthread_mutex_t mut;
};  

ThreadPool* ThreadPool::tp= nullptr;
pthread_mutex_t ThreadPool::mut= PTHREAD_MUTEX_INITIALIZER;

